package code;

import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiType;
import utils.AndroidFileUtils;
import utils.StringUtils;

import java.io.File;
import java.util.List;
import java.util.Map;

public class CodeFactory {
    /**
     * 生成 DatabaseHelper 初始代码
     *
     * <pre>
     * package {package}.db;
     *
     * import android.content.Context;
     * import android.database.sqlite.SQLiteDatabase;
     * import android.database.sqlite.SQLiteOpenHelper;
     *
     * public class DatabaseHelper extends SQLiteOpenHelper {
     *     private static String DB_NAME = "INPUT YOUR DB FILE NAME";
     *     private static final int DB_VERSION = 1;
     *
     *     private static volatile DatabaseHelper instance = null;
     *
     *     public static DatabaseHelper getInstance(Context context) {
     *         if (instance == null) {
     *             synchronized (DatabaseHelper.class) {
     *                 if (instance == null) {
     *                     instance = new DatabaseHelper(context);
     *                 }
     *             }
     *         }
     *         return instance;
     *     }
     *
     *     private DatabaseHelper(Context context) {
     *         super(context, DB_NAME, null, DB_VERSION);
     *     }
     *
     *     @Override
     *     public void onCreate(SQLiteDatabase db) {
     *     }
     *
     *     @Override
     *     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     *     }
     * }
     * </pre>
     */
    public static String genSQLiteOpenHelperInitCode(Project project) {
        return StringUtils.formatSingleLine(0, "package " + AndroidFileUtils.getAppPackageNameDir(project) + ".db;") +
                "\n" +
                StringUtils.formatSingleLine(0, "import android.content.Context;") +
                StringUtils.formatSingleLine(0, "import android.database.sqlite.SQLiteDatabase;") +
                StringUtils.formatSingleLine(0, "import android.database.sqlite.SQLiteOpenHelper;") +
                "\n" +
                StringUtils.formatSingleLine(0, "public class DatabaseHelper extends SQLiteOpenHelper {") +
                StringUtils.formatSingleLine(1, "private static String DB_NAME = \"INPUT YOUR DB FILE NAME\";") +
                StringUtils.formatSingleLine(1, "private static final int DB_VERSION = 1;") +
                StringUtils.formatSingleLine(1, "private static volatile DatabaseHelper instance = null;") +
                "\n" +
                StringUtils.formatSingleLine(1, "public static DatabaseHelper getInstance(Context context) {") +
                StringUtils.formatSingleLine(2, "if (instance == null) {") +
                StringUtils.formatSingleLine(3, "synchronized (DatabaseHelper.class) {") +
                StringUtils.formatSingleLine(4, "if (instance == null) {") +
                StringUtils.formatSingleLine(5, "instance = new DatabaseHelper(context);") +
                StringUtils.formatSingleLine(4, "}") +
                StringUtils.formatSingleLine(3, "}") +
                StringUtils.formatSingleLine(2, "}") +
                StringUtils.formatSingleLine(2, "return instance;") +
                StringUtils.formatSingleLine(1, "}") +
                "\n" +
                StringUtils.formatSingleLine(1, "private DatabaseHelper(Context context) {") +
                StringUtils.formatSingleLine(2, "super(context, DB_NAME, null, DB_VERSION);") +
                StringUtils.formatSingleLine(1, "}") +
                "\n" +
                StringUtils.formatSingleLine(1, "@Override") +
                StringUtils.formatSingleLine(1, "public void onCreate(SQLiteDatabase db) {") +
                StringUtils.formatSingleLine(1, "}") +
                "\n" +
                StringUtils.formatSingleLine(1, "@Override") +
                StringUtils.formatSingleLine(1, "public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {") +
                StringUtils.formatSingleLine(1, "}") +
                "}";
    }

    /**
     * 生成创建数据库表单方法代码
     * 表名根据实体类名转化而来（实体驼峰命令转化为下划线命名规则，例如UserInfo -> user_info）
     * 如果没有设置主键，默认增加id属性，为主键
     * 其他属性名为实体类的成员变量名称
     * <pre>
     * String sql = "CREATE TABLE IF NOT EXISTS "
     *         "user_info"
     *         + "("
     *         + "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
     *         + "name TEXT,"
     *         + "age TEXT,"
     *         + "isMan TEXT"
     *         + "address TEXT"
     *         + "tel TEXT"
     *        + ")";
     * </pre>
     */
    public static String genCreateTableCode(PsiClass psiClass, Map<String, String> map, PsiField priKeyField) {
        String tableName = StringUtils.camelToUnderline(psiClass.getName());
        StringBuilder sb = new StringBuilder();
        sb.append(StringUtils.formatSingleLine(0, "public void create" + psiClass.getName() + "Table(SQLiteDatabase db) {"));
        sb.append(StringUtils.formatSingleLine(1, "String sql = \"CREATE TABLE IF NOT EXISTS\""));
        sb.append(StringUtils.formatSingleLine(3, "+ \" " + tableName + " (\""));
        if (priKeyField == null) {
            // 默认主键
            sb.append(StringUtils.formatSingleLine(3, "+ \" _id INTEGER PRIMARY KEY AUTOINCREMENT,\""));
        } else {
            sb.append(StringUtils.formatSingleLine(3, "+ \" _id INTEGER,\""));
        }
        for (String key : map.keySet()) {
            if (priKeyField != null && priKeyField.getName().equals(key)) {
                // 有自定义主键
                sb.append(StringUtils.formatSingleLine(3, "+ \" " + key + " TEXT PRIMARY KEY,\""));
            } else {
                sb.append(StringUtils.formatSingleLine(3, "+ \" " + key + " TEXT ,\""));
            }
        }
        sb.replace(sb.lastIndexOf(",\""), sb.lastIndexOf(",\"") + 2, "\"\n\t\t+ \")\";");
        sb.append(StringUtils.formatSingleLine(1, "db.execSQL(sql);"));
        sb.append(StringUtils.formatSingleLine(0, "}"));
        return sb.toString();
    }


    /**
     * 生成XXXDao.java ，增删改查方法。
     */
    public static String genDaoCode(Project project, PsiClass psiClass, String entryPackageName, Map<String, String> map, PsiField priKeyField) {
        String daoClassName = psiClass.getName() + "Dao";
        StringBuilder sb = new StringBuilder();
        sb.append(StringUtils.formatSingleLine(0, "package " + AndroidFileUtils.getAppPackageNameDir(project) + ".db;"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(0, "import android.content.ContentValues;"));
        sb.append(StringUtils.formatSingleLine(0, "import android.database.Cursor;"));
        sb.append(StringUtils.formatSingleLine(0, "import android.database.sqlite.SQLiteDatabase;"));
        sb.append(StringUtils.formatSingleLine(0, "import android.database.sqlite.SQLiteStatement;"));
        sb.append(StringUtils.formatSingleLine(0, "import android.content.Context;"));

        sb.append(StringUtils.formatSingleLine(0, "import " + entryPackageName + "." + psiClass.getName() + ";"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(0, "import java.util.ArrayList;"));
        sb.append(StringUtils.formatSingleLine(0, "import java.util.List;"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(0, "public class " + daoClassName + " {"));
        sb.append(StringUtils.formatSingleLine(1, "private DatabaseHelper helper;"));
        sb.append(StringUtils.formatSingleLine(1, "private static volatile " + daoClassName + " instance = null;"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(1, "public static " + daoClassName + " getInstance(Context context) {"));
        sb.append(StringUtils.formatSingleLine(2, "if (instance == null) {"));
        sb.append(StringUtils.formatSingleLine(3, "synchronized (" + daoClassName + ".class) {"));
        sb.append(StringUtils.formatSingleLine(4, "if (instance == null) {"));
        sb.append(StringUtils.formatSingleLine(5, "instance = new " + daoClassName + "(context);"));
        sb.append(StringUtils.formatSingleLine(4, "}"));
        sb.append(StringUtils.formatSingleLine(3, "}"));
        sb.append(StringUtils.formatSingleLine(2, "}"));
        sb.append(StringUtils.formatSingleLine(2, "return instance;"));
        sb.append(StringUtils.formatSingleLine(1, "}"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(1, "private " + daoClassName + "(Context context) {"));
        sb.append(StringUtils.formatSingleLine(2, "helper = DatabaseHelper.getInstance(context);"));
        sb.append(StringUtils.formatSingleLine(1, "}"));
        sb.append("\n");
        genDaoAddMethod(psiClass, map, sb); // add data
        sb.append("\n");
        genDaoGetListMethod(psiClass, map, sb); // get data list
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(0, "}"));
        return sb.toString();
    }

    /**
     * 添加数据
     */
    public static void genDaoAddMethod(PsiClass psiClass, Map<String, String> map, StringBuilder sb) {
        sb.append(StringUtils.formatSingleLine(1, "// 添加一条数据到数据库"));
        sb.append(StringUtils.formatSingleLine(1, "public void add" + psiClass.getName() + "(" + psiClass.getName() + " data) {"));
        sb.append(StringUtils.formatSingleLine(2, "SQLiteDatabase db = helper.getWritableDatabase();"));
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(2, "ContentValues value = new ContentValues();"));
        for (String key : map.keySet()) {
            String text = "value.put(\"" + key + "\"," + genDataGetStr("data", key, map.get(key)) + ");";
            sb.append(StringUtils.formatSingleLine(2, text));
        }
        sb.append("\n");
        sb.append(StringUtils.formatSingleLine(2, "db.insert(\"" + StringUtils.camelToUnderline(psiClass.getName()) + "\", null, value);"));
        sb.append(StringUtils.formatSingleLine(1, "}"));
    }

    /**
     * 获取数据
     */
    public static void genDaoGetListMethod(PsiClass psiClass, Map<String, String> map, StringBuilder sb) {
        sb.append(StringUtils.formatSingleLine(1, "// 返回数据库的所有数据"));
        sb.append(StringUtils.formatSingleLine(1, "public List<" + psiClass.getName() + "> get" + psiClass.getName() + "List() {"));
        sb.append(StringUtils.formatSingleLine(2, "SQLiteDatabase db = helper.getReadableDatabase();"));
        sb.append(StringUtils.formatSingleLine(2, "List<" + psiClass.getName() + "> list = new ArrayList<>();"));
        sb.append(StringUtils.formatSingleLine(2, "Cursor cursor = null;"));
        sb.append(StringUtils.formatSingleLine(2, "try {"));
        sb.append(StringUtils.formatSingleLine(3, "cursor = db.query(\"" + StringUtils.camelToUnderline(psiClass.getName()) + "\","));
        sb.append(StringUtils.formatSingleLine(5, "null,"));
        sb.append(StringUtils.formatSingleLine(5, "null,"));
        sb.append(StringUtils.formatSingleLine(5, "null,"));
        sb.append(StringUtils.formatSingleLine(5, "null,"));
        sb.append(StringUtils.formatSingleLine(5, "null,"));
        sb.append(StringUtils.formatSingleLine(5, "null);"));
        sb.append(StringUtils.formatSingleLine(3, "if (cursor != null && cursor.moveToFirst()) {"));
        sb.append(StringUtils.formatSingleLine(4, "do {"));
        sb.append(StringUtils.formatSingleLine(5, "" + psiClass.getName() + " data = new " + psiClass.getName() + "();"));
        for (String key : map.keySet()) {
            sb.append(StringUtils.formatSingleLine(5, genSetDataStr("data", key, map.get(key))));
        }
        sb.append(StringUtils.formatSingleLine(5, "list.add(data);"));
        sb.append(StringUtils.formatSingleLine(4, "} while (cursor.moveToNext());"));
        sb.append(StringUtils.formatSingleLine(3, "}"));
        sb.append(StringUtils.formatSingleLine(2, "} finally {"));
        sb.append(StringUtils.formatSingleLine(3, "if (cursor != null) cursor.close();"));
        sb.append(StringUtils.formatSingleLine(2, "}"));
        sb.append(StringUtils.formatSingleLine(2, "return list;"));
        sb.append(StringUtils.formatSingleLine(1, "}"));
    }


    /**
     * 获取实体对象的成员变量值
     * boolean值存储方式：true 存 “1” ，false 存 “0”。
     *
     * @param data 实体对象的变量名
     * @param name 实体对象的成员变量名
     * @return
     */
    private static String genDataGetStr(String data, String name, String type) {
        String getMethod;
        if (name.startsWith("is")) {
            getMethod = name + "()";
        } else {
            getMethod = "get" + StringUtils.firstToUpperCase(name) + "()";
        }
        String value = data + "." + getMethod;
        if (type.equals(PsiType.BOOLEAN.getName())) {
            return value + "?1:0";
        }
        return value;
    }

    /**
     * 设置实体对象的成员变量值
     *
     * @param data 实体对象的变量名
     * @param name 实体对象的成员变量名
     * @return
     */
    private static String genSetDataStr(String data, String name, String real_type) {
        String type;
        switch (real_type) {
            case "int":
            case "Integer":
                type = "Int";
                break;
            case "long":
            case "Long":
                type = "Long";
                break;
            case "float":
            case "Float":
                type = "Float";
                break;
            case "double":
            case "Double":
                type = "Double";
                break;
            default:
                type = "String";
                break;
        }

        String text = data + ".%s(cursor.get%s(cursor.getColumnIndex(\"%s\")));";
        String setMethod = "set" + StringUtils.firstToUpperCase(name);
        if (name.startsWith("is")) {
            setMethod = setMethod.replaceFirst("Is", "");
        }
        if (real_type.equals(PsiType.BOOLEAN.getName())) {
            return String.format(data + ".%s(\"1\".equals(cursor.get%s(cursor.getColumnIndex(\"%s\"))));", setMethod, type, name);
        } else {
            return String.format(text, setMethod, type, name);
        }
    }
}
